package ru.spbu.math.android.cbrf.dataprovider;

import java.util.Date;
import java.util.StringTokenizer;

import ru.spbu.math.android.cbrf.model.Rate;
import ru.spbu.math.android.cbrf.model.RateType;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class DatabaseProvider {

	private SQLiteDatabase database;
	private static final String TABLE_NAME = "rates";

	private static final String RATE_TYPE = "target";
	private static final String VALUE = "value";
	private static final String DATE = "date";
	private static final String DIFF = "difference";

	private static final String TAG = "DatabaseProvider";

	private ProviderManager providerManager;

	/**
	 * constructor
	 * 
	 * @param context
	 * @throws SQLiteException
	 */
	public DatabaseProvider(Context context, ProviderManager providerManager)
			throws SQLiteException {

		this.providerManager = providerManager;

		RateDatabaseOpenHelper open = new RateDatabaseOpenHelper(context);
		database = open.getWritableDatabase();
	}

	private static class RateDatabaseOpenHelper extends SQLiteOpenHelper {

		private static final String DATABASE_NAME = "the_price_of_money.db";

		private static final String DATABASE_CREATE = String
				.format("CREATE TABLE %s ( %s TEXT PRIMARY KEY, %s TEXT, %s TEXT, %s TEXT);",
						TABLE_NAME, RATE_TYPE, VALUE, DIFF, DATE);

		private static final int DATABASE_VERSION = 1;

		RateDatabaseOpenHelper(Context context) {
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
		}

		@Override
		public void onCreate(SQLiteDatabase database) {
			database.execSQL(DATABASE_CREATE);
		}

		@Override
		public void onUpgrade(SQLiteDatabase database, int oldVersion,
				int newVersion) {
			database.execSQL("DROP TABLE IF EXISTS" + TABLE_NAME);
			onCreate(database);
		}
	}

	/**
	 * @param rate
	 *            to be added into database
	 */
	public void addLatestRate(Rate rate) {

		Rate latestRate = getLatestRate(rate.getResource());
		if ((latestRate == null)
				|| (rate.getDate().after(latestRate.getDate()))) {
			addRate(rate);
		}
	}

	private void addRate(Rate rate) {

		if (rate != null) {
			ContentValues values = new ContentValues();
			values.put(RATE_TYPE,
					providerManager.getExternalIdByRateType(rate.getResource()));
			values.put(VALUE, rate.getValue());
			values.put(DATE, dateToTimestring(rate.getDate()));
			values.put(DIFF, rate.getDifference());
			database.replace(TABLE_NAME, null, values);

			Log.d(TAG, "Add rate into database: " + rate.toString());
		}
	}

	/**
	 * @param rateTypeId
	 * @return latest Rate with selected rateType
	 */
	public Rate getLatestRate(RateType rateType) {

		String[] selectColumns = { RATE_TYPE, VALUE, DATE, DIFF };

		String selection = String.format("( %s = \"%s\" )", RATE_TYPE,
				providerManager.getExternalIdByRateType(rateType));

		Cursor cursor = database.query(TABLE_NAME, selectColumns, selection,
				null, null, null, null);
		
		if (!cursor.moveToFirst()) {
			Log.d(TAG, "Getting Latest Rate Failed");
			cursor.close();
			return null;
		} else {
			Log.d(TAG, "Getting Latest Rate");
			double value = Double.parseDouble(cursor.getString(cursor
					.getColumnIndex(VALUE)));

			Date date = timestringToDate(cursor.getString(cursor
					.getColumnIndex(DATE)));
			double diff = Double.parseDouble(cursor.getString(cursor
					.getColumnIndex(DIFF)));
			cursor.close();

			return new Rate(rateType, value, diff, date);
		}
	}

	// make time string "YYYY-MM-DD HH:MM" from Date

	private String dateToTimestring(Date date) {

		String timestring = "";

		int year = date.getYear() + 1900;
		timestring += year;

		int month = date.getMonth() + 1;
		if (month < 10) {
			timestring += "-0" + month;
		} else {
			timestring += "-" + month;
		}

		if (date.getDate() < 10) {
			timestring += "-0" + date.getDate();
		} else {
			timestring += "-" + date.getDate();
		}

		if (date.getHours() < 10) {
			timestring += " 0" + date.getHours();
		} else {
			timestring += " " + date.getHours();
		}

		if (date.getMinutes() < 10) {
			timestring += ":0" + date.getMinutes();
		} else {
			timestring += ":" + date.getMinutes();
		}

		return timestring;
	}

	// build Date from time string "YYYY-MM-DD HH:MM"

	private Date timestringToDate(String timestring) {
		Date date = new Date();

		StringTokenizer st = new StringTokenizer(timestring, "- :");
		date.setYear(Integer.parseInt(st.nextToken()) - 1900);
		date.setMonth(Integer.parseInt(st.nextToken()) - 1);
		date.setDate(Integer.parseInt(st.nextToken()));
		date.setHours(Integer.parseInt(st.nextToken()));
		date.setMinutes(Integer.parseInt(st.nextToken()));

		return date;
	}
}
